package nl.ru.rd.facedetection.nnbfd;

import java.util.ArrayList;
import java.awt.Image;
import java.awt.image.BufferedImage;

/**
 * A container a factory for a set of Windows
 * 
 * @see Window
 * 
 * @author Christiaan Thijssen s0814970
 * @author Kevin Reintjes s0814954
 * @author Wouter Geraedts (s0814857 - wgeraedts) PGP 66AA5935
 */
public class Windows
{
	/**
	 * The factor by which to enlarge the image each time a new series of windows is generated.
	 */
	public static final double resizeFactor = 1.2;

	/**
	 * The number of times to generate and resize series of windows.
	 */
	public static final short numSizes = 20;

	private Matrix resizedMatrixes[] = new Matrix[numSizes];
	private ArrayList<Window> windows = new ArrayList<Window>();

	/**
	 * Create series of Windows from an image.
	 */
	public Windows(BufferedImage colorImage)
	{
		this.initializeMatrices(colorImage);

		System.out.println("Initializing windows");
		this.initializeWindows();
	}

	/**
	 * @return The Windows
	 */
	public ArrayList<Window> getWindows()
	{
		return this.windows;
	}

	/**
	 * Resize function for resizing the image multiple times.
	 * 
	 * @param imageMatrix
	 *            The image in a matrix.
	 */
	private BufferedImage[] resize(BufferedImage colorImage)
	{
		double factor = 1;
		BufferedImage[] result = new BufferedImage[numSizes];

		for(int i = 0; i < numSizes; i++)
		{
			result[i] = this.resizeImage(colorImage, factor);
			factor *= resizeFactor;
		}

		return result;
	}

	private void initializeMatrices(BufferedImage colorImage)
	{
		System.out.println("Resizing image");
		BufferedImage[] images = this.resize(colorImage);

		System.out.println("Converting images to grayscale");
		for(int i = 0; i < images.length; i++)
			this.resizedMatrixes[i] = Preprocessor.toMatrix(images[i]);
	}

	/**
	 * Resizes an image with a certain factor.
	 * 
	 * @param factor
	 *            The resize factor.
	 */
	private BufferedImage resizeImage(BufferedImage colorImage, double factor)
	{
		int imageWidth = colorImage.getWidth();
		int imageHeight = colorImage.getHeight();
		int nWidth = (int) Math.round(imageWidth / factor);
		int nHeight = (int) Math.round(imageHeight / factor);

		Image temp = colorImage.getScaledInstance(nWidth, nHeight, Image.SCALE_SMOOTH);
		BufferedImage image = new BufferedImage(nWidth, nHeight, BufferedImage.TYPE_INT_RGB);
		image.getGraphics().drawImage(temp, 0, 0, null);

		return image;
	}

	/**
	 * Method to create windows out of the resized image matrices.
	 */
	private void initializeWindows()
	{
		for(int i = 10; i < numSizes; i++)
		{
			Matrix matrix = this.resizedMatrixes[i];
			for(int x = 0; x < matrix.getWidth() - Window.size + 1; x++)
				for(int y = 0; y < matrix.getHeight() - Window.size + 1; y++)
					this.windows.add(new Window(matrix, i, x, y));
		}
	}
}